<?php

/**
 * Класс -- дата и время
 *
 */
class RL_CyrDate
{

	var $year=NULL;
	var $month=NULL;
	var $day=NULL;
	var $hour=NULL;
	var $minute=NULL;
	var $second=NULL;

	static public $cyr_months = array(
		1 => 'января',
		2 => 'февраля',
		3 => 'марта',
		4 => 'апреля',
		5 => 'мая',
		6 => 'июня',
		7 => 'июля',
		8 => 'августа',
		9 => 'сентября',
		10 => 'октября',
		11 => 'ноября',
		12 => 'декабря',
	);
	static $en_months = array(
		1 => 'january',
		2 => 'february',
		3 => 'march',
		4 => 'april',
		5 => 'may',
		6 => 'june',
		7 => 'july',
		8 => 'august',
		9 => 'september',
		10 => 'october',
		11 => 'november',
		12 => 'december',
	);
	static $cyr_month = array(
		1 => 'январь',
		2 => 'февраль',
		3 => 'март',
		4 => 'апрель',
		5 => 'май',
		6 => 'июнь',
		7 => 'июль',
		8 => 'август',
		9 => 'сентябрь',
		10 => 'октябрь',
		11 => 'ноябрь',
		12 => 'декабрь',
	);
	static $en_month = array(
		1 => 'January',
		2 => 'February',
		3 => 'March',
		4 => 'April',
		5 => 'May',
		6 => 'June',
		7 => 'July',
		8 => 'August',
		9 => 'September',
		10 => 'October',
		11 => 'November',
		12 => 'December',
	);
	static $en_week = array(
		0 => 'Monday',
		1 => 'Tuesday',
		2 => 'Wednesday',
		3 => 'Thursday',
		4 => 'Friday',
		5 => 'Saturday',
		6 => 'Sunday',
	);
	static $cyr_quarter = array(
		1 => 'I квартал', 
		2 => 'II квартал', 
		3 => 'III квартал', 
		4 => 'IV квартал'
	);
	static $fmts = array(
		'Q'=>'quarter',
		'Y'=>'year',
		'y'=>'year_short',
		'm'=>'month',
		'M'=>'months_str',
		'N'=>'month_str',
		'd'=>'day',
		'j'=>'day_short',
		'H'=>'hour',
		'i'=>'minute',
		's'=>'second',
		'B'=>'month_str',
		'b' => 'month_str3',
		'A' => 'week_str',
		'a' => 'week_str3',
		'z' => 'timezone',
	);
	static $prsrs = array(
		'Y'=>array('\d{4}',   'setYear'),
		'm'=>array('\d{1,2}', 'setMonth'),
		'd'=>array('\d{1,2}', 'setDay'),
		'H'=>array('\d{1,2}', 'setHour'),
		'i'=>array('\d{1,2}', 'setMinute'),
		's'=>array('\d{1,2}', 'setSecond'),
	);

	//!a constructor
	/** 
	 * Создать объект RL_CyrDate 
	 *
	 * @param string $date строка в формате %Y-%m-%d %H:%i:%s
	 */
	function __construct($date=NULL)
	{
		if(isset($date)) $this->fromStr('%Y-%m-%d %H:%i:%s', $date);
	}

	//!a constructor
	/** 
	 * Создать объект RL_CyrDate из строки $str, содержащей дату в формате $fmt
	 *
	 * @param string $fmt формат даты в $str
	 * @param string $str дата в виде строки
	 *
	 * @return object RL_CyrDate
	 */
	function newFromStr($fmt, $str)
	{
		$o = new RL_CyrDate();
		return $o->fromStr($fmt, $str);
	}

	public function newFromTimestamp($timestamp)
	{
		$o = new RL_CyrDate();
		return $o->fromTimestamp($timestamp);
	}

	function fromTimestamp($timestamp)
	{
		return $this->fromStr('%Y %m %d %H %i %s', date('Y m d H i s', $timestamp));
	}

	// compability
	public function createFromStr($fmt, $str)
	{
		return RL_CyrDate::newFromStr($fmt, $str);
	}

	function dayStart()
	{
		$this->hour = 0;
		$this->minute = 0;
		$this->second = 1;
		return $this;
	}
	function dayEnd()
	{
		$this->hour = 23;
		$this->minute = 59;
		$this->second = 59;
		return $this;
	}
	function getDayOfWeek()
	{
		$now = mktime($this->hour, $this->minute, $this->second, 
			$this->month, $this->day, $this->year);
		$day_of_week = intval(date('w',  // 0 - sunday, 1 - monday
			$now));
		$day_of_week = (int)(($day_of_week + 6) % 7); // 0 - monday, 6 - sunday
		return $day_of_week;
	}
	function weekStart()
	{
		$this->dayStart();
		$this->day = $this->day - $this->getDayOfWeek();

		$this->fromStr('%Y %m %d %H %i %s',
			date('Y m d H i s',
			mktime($this->hour, $this->minute, $this->second, 
				$this->month, $this->day, $this->year)));
		return $this;
	}
	function weekEnd()
	{
		$this->dayEnd();
		$this->day = $this->day + (6 - $this->getDayOfWeek());

		$this->fromStr('%Y %m %d %H %i %s',
			date('Y m d H i s',
			mktime($this->hour, $this->minute, $this->second, 
				$this->month, $this->day, $this->year)));
		return $this;
	}
	function monthStart()
	{
		$this->dayStart();
		$this->day = 1;
		return $this;
	}
	function monthEnd()
	{
		$this->dayEnd();
		$this->day = intval(date('t', mktime(0, 0, 0, $this->month, 1, $this->year)));
		return $this;
	}
	function quarterStart()
	{
		$this->month = ($this->getQuarter()) * 3 - 2;
		$this->monthStart();
		return $this;
	}
	function quarterEnd()
	{
		$this->month = ($this->getQuarter()) * 3;
		$this->monthEnd();
		return $this;
	}
	//!a constructor
	/** 
	 * Создать объект RL_CyrDate для текущего времени
	 *
	 * @return object RL_CyrDate
	 */
	public function newNow()
	{
		$o = new RL_CyrDate();
		return $o->now();
	}
	// compability, don't use
	public function createNow()
	{
		return RL_CyrDate::newNow();
	}

	//!a manipulator
	/** 
	 * Инициализировать объект текущим временем
	 *
	 * @return object RL_CyrDate
	 */
	public function now()
	{
		return $this->fromStr('%Y %m %d %H %i %s', date('Y m d H i s'));
	}

	public function date($fmt, $date)
	{
		$o = new RL_CyrDate($date);
		return $o->format($fmt);
	}

	function format($fmt)
	{
		$result = preg_replace_callback('#%([a-zA-Z])#', array($this, '_callback'), $fmt);
		return $result;
	}

	//!a manipulator
	/** 
	 * Инициализировать объект из строки $str, содержащей дату в формате $fmt
	 *
	 * @param string $fmt формат даты в $str
	 * @param string $str дата в виде строки
	 *
	 * @return object RL_CyrDate
	 */
	public function fromStr($fmt, $str)
	{
		$res = NULL;
		$this->parser = array();
		$fmt_re = preg_replace_callback('#%([a-zA-Z])#', array($this, '_fromstr'), $fmt);
		if (preg_match('#^'.$fmt_re.'$#', $str, $matches))
		{
			if (True === $this->_fromstr_prs($matches))
				$res = $this;
		}
		unset ($this->parser);
		return $res;
	}

	function getQuarter() { return intval($this->month / 4) + 1; }
	// renders/getters:
	function quarter() { return $this->_toStr('quarter', $this->getQuarter()); }
	function year() { return sprintf('%04d', $this->year); }
	function year_short() { return sprintf('%02d', $this->year % 100); }
	function month() { return sprintf('%02d', $this->month); }
	function day() { return sprintf('%02d', $this->day); }
	function day_short() { return sprintf('%d', $this->day); }
	function hour() { return sprintf('%02d', $this->hour); }
	function minute() { return sprintf('%02d', $this->minute); }
	function second() { return sprintf('%02d', $this->second); }

	function months_str() { return $this->_toStr('months', $this->month); }
	function month_str() { return $this->_toStr('month', $this->month); }
	function month_str3() { return mb_substr($this->month_str(), 0, 3); }
	function week_str() { return $this->_toStr('week', $this->getDayOfWeek()); }
	function week_str3() { return substr($this->week_str(), 0, 3); }
	
	function unix_mark() { return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year); }

	// setters:
	function setYear($value) { $this->year = intval($value); }
	function setMonth($value) { $this->month = intval($value); }
	function setDay($value) { $this->day = intval($value); }
	function setHour($value) { $this->hour = intval($value); }
	function setMinute($value) { $this->minute = intval($value); }
	function setSecond($value) { $this->second = intval($value); }

	function getIsMorning() { return ($this->hour() >= 4 && $this->hour() < 8); } 
	function getIsDay() { return ($this->hour() >= 8 && $this->hour() < 18); } 
	function getIsEvening() { return ($this->hour() >= 18 && $this->hour() < 22); } 
	function getIsNight() { return ($this->hour() >= 22 || $this->hour() < 4); } 

	function timezone() 
	{ 
		return (($this->tz >= 0) ? '+' : '-').sprintf('%04d', $this->tz * 100); 
	}
	function getRss()
	{
		$fmt = '%a, %d %b %Y %H:%i:%s %z';

		$l_tmp = NULL; if (!isset($this->lang)) $l_tmp = $this->lang;
		$this->lang = 'en';
		$out = $this->format($fmt);
		if ($l_tmp !== NULL) $this->lang = $l_tmp;

		return $out;
	}

	function mktime($hour=0, $minute=0, $second=0, $month=0, $day=0, $year=0)
	{
		return mktime(
			$this->hour() + $hour, 
			$this->minute() + $minute, 
			$this->second() + $second, 
			$this->month() + $month, 
			$this->day() + $day, 
			$this->year() + $year);
	}

	// private: 
	function _callback($matches)
	{
		$value = $matches[1];
		return array_key_exists($value, RL_CyrDate::$fmts) 
			? call_user_func(array($this, RL_CyrDate::$fmts[$value]))
			: $value;
	}
	function _fromstr($matches)
	{
		$value = $matches[1];
		if( array_key_exists($value, RL_CyrDate::$prsrs) )
		{
			$this->parser[] = $value;
			$value = '('.RL_CyrDate::$prsrs[$value][0].')';
		}
		return $value;
	}
	function _fromstr_prs($matches)
	{
		if (count($matches) - 1 !== count($this->parser)) return NULL;

		for($i=0, $c=count($this->parser); $i<$c; $i++)
		{
			call_user_func(array($this, RL_CyrDate::$prsrs[$this->parser[$i]][1]), $matches[$i+1]);
		}

		return True;
	}
	function _toStr($name, $value)
	{
		$lang = (isset($this->lang) 
			? $this->lang 
			: (
				isset($this->ctx->lang) 
				? $this->ctx->lang 
				: 'cyr'));
		$attr = $lang.'_'.$name; 
		$src = RL_CyrDate::$$attr;
		return $src[$value];
	}
}


?>
